package com.ouc.eddyAlgorithm.service.impl;

import com.ouc.common.constant.VariableName;
import com.ouc.common.entity.FlowData;
import com.ouc.common.entity.Header;
import com.ouc.common.entity.NcData;
import com.ouc.common.entity.NcGridData;
import com.ouc.common.ncRead.NcDao;
import com.ouc.common.utils.Arith;
import com.ouc.common.utils.ArrayUtils;
import com.ouc.common.utils.MathUtils;
import com.ouc.common.utils.ToPictureUtil;
import com.ouc.eddyAlgorithm.service.FactorAlgorithmService;
import com.ouc.visualization.entity.ContourData;
import com.ouc.visualization.entity.FactorCondition;
import com.ouc.visualization.service.NcPictServiceVisualization;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import ucar.ma2.InvalidRangeException;
import ucar.nc2.NetcdfFile;
import ucar.nc2.Variable;

import java.awt.image.BufferedImage;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import static com.ouc.common.constant.NcConstants.*;


/**
 * 要素可视化服务层
 *
 * @author B504
 */
@Service
@CacheConfig(cacheNames = {"ncData_service_cache"}, keyGenerator = "myKeyGenerator")
@Slf4j
public class FactorAlgorithmServiceImpl implements FactorAlgorithmService {


  @Autowired
  private NcPictServiceVisualization ncPictServiceVisualization;

  @Autowired
  NcDao ncDao;

  @Override
  @Cacheable
  public ContourData<NcGridData> getContourData(NetcdfFile ncFile, String variableName, Float[] lon, Float[] lat, Integer depth) throws Exception {
    NcGridData ncGridData = ncDao.getNcGridData(ncFile, variableName, lon, lat, depth);
    ContourData<NcGridData> ncGridDataContourData = new ContourData<>();
    if (ncGridData == null) {
      return ncGridDataContourData;
    }
    float[] minAndMax = MathUtils.minAndMax(ncGridData.getValues());
    float[] listLon = ncGridData.getListLon();
    int lonLength = listLon.length;
    float lonInterval = BigDecimal.valueOf(listLon[1]).subtract(BigDecimal.valueOf(listLon[0])).setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();//四舍五入保留两位小数
    float startLon = listLon[0];
    float[] listLat = ncGridData.getListLat();
    int latLength = listLat.length;
    float latInterval = BigDecimal.valueOf(listLat[1]).subtract(BigDecimal.valueOf(listLat[0])).setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();//四舍五入保留两位小数
    float startLat = listLat[0];
    ncGridDataContourData = new ContourData<>(ncGridData, minAndMax[0], minAndMax[1],
        lonLength, latLength, lonInterval, latInterval, startLon, startLat, variableName);

    return ncGridDataContourData;

  }

  @Override
  @Cacheable
  public ContourData<NcGridData> getNcContourData(NetcdfFile ncFile, String variableName) throws IOException, InvalidRangeException {
    return getNcContourData(ncFile, variableName, null);
  }

  @Override
  @Cacheable
  public ContourData<NcGridData> getNcContourData(NetcdfFile ncFile, String variableName, Integer depth) throws IOException, InvalidRangeException {
    return getNcContourData(ncFile, variableName, null, null, depth);
  }

  @Override
  @Cacheable
  public ContourData<NcGridData> getNcContourData(NetcdfFile ncFile, String variableName, Float[] lon, Float[] lat) throws IOException, InvalidRangeException {
    return getNcContourData(ncFile, variableName, lon, lat, null);
  }

  @Override
  @Cacheable
  public ContourData<NcGridData> getNcContourData(NetcdfFile ncFile, String variableName, Float[] lon, Float[] lat, Integer depth) throws IOException, InvalidRangeException {
    return getNcContourData(ncFile, variableName, lon, lat, depth, null);
  }

  @Override
  @Cacheable
  public ContourData<NcGridData> getNcContourData(NetcdfFile ncFile, String variableName, Float[] lon, Float[] lat, Integer depth, Integer time) throws IOException, InvalidRangeException {
    NcGridData ncGridData = ncDao.getNcGridData(ncFile, variableName, lon, lat, depth, time);
    ContourData<NcGridData> contourData = new ContourData<>();
    if (ncGridData == null || ncGridData.getValues() == null) {
      return contourData;
    }

    float[] minAndMax = MathUtils.minAndMax(ncGridData.getValues());
    float[] listLon = ncGridData.getListLon();
    int lonLength = listLon.length;
    float lonInterval = BigDecimal.valueOf(listLon[1]).subtract(BigDecimal.valueOf(listLon[0])).setScale(4, BigDecimal.ROUND_HALF_UP).floatValue();//四舍五入保留两位小数
    float startLon = listLon[0];
    float[] listLat = ncGridData.getListLat();
    int latLength = listLat.length;
    float latInterval = BigDecimal.valueOf(listLat[1]).subtract(BigDecimal.valueOf(listLat[0])).setScale(4, BigDecimal.ROUND_HALF_UP).floatValue();//四舍五入保留两位小数
    float startLat = listLat[0];
    contourData = new ContourData<>(ncGridData, minAndMax[0], minAndMax[1],
        lonLength, latLength, lonInterval, latInterval, startLon, startLat, variableName);

    return contourData;
  }

  @Override
  @Cacheable
  public void writeLevelMeter(NetcdfFile ncFile, String filePath) throws IOException, InvalidRangeException {
    Variable variable = ncDao.getVariable(ncFile, VariableName.LEVEL);
    NcGridData ncGridData = ncDao.getNcGridData(ncFile, variable.getFullName());
    float[] depth = ncGridData.getDepth();
    StringBuilder sb = new StringBuilder();
    sb.append("层级:深度(米)").append("\r\n");

    try (BufferedWriter bw = new BufferedWriter(new FileWriter(filePath))) {
      for (int i = 0; i < depth.length; i++) {
        sb.append(i).append(":")
            .append(depth[i]).append("\r\n");
        bw.write(sb.toString());
        sb = new StringBuilder();
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  @Override
  @Cacheable
  public FlowData getParticleFlowDataOfFlowByLimit(NetcdfFile ncFile, float lonStart, float lonEnd, float latStart, float latEnd, Integer level, String variableName, int dilution, int exaggerate, boolean reverseFlag, boolean startByZero) throws IOException, InvalidRangeException {
    return getParticleFlowDataOfFlowByLimit(ncFile, lonStart, lonEnd, latStart, latEnd, level, null, variableName, dilution, exaggerate, reverseFlag, startByZero);
  }

  @Override
  @Cacheable
  public FlowData getParticleFlowDataOfFlowByLimit(NetcdfFile ncFile, float lonStart, float lonEnd, float latStart, float latEnd, Integer level, Integer time, String variableName, int dilution, int exaggerate, boolean reverseFlag, boolean startByZero) throws IOException, InvalidRangeException {
    Map<String, NcData> ncDataOfLimit = ncDao.getNcDataOfLimitFromVariable(ncFile, variableName, new Float[]{lonStart, lonEnd}, new Float[]{latStart, latEnd}, level, time);
    if (ncDataOfLimit == null) {
      return null;
    }
    /**
     * 获取原始经纬度
     * 和数据
     */
    float[] lat = ncDataOfLimit.get(ncDao.getVariable(ncFile, VariableName.LAT).getShortName()).getData1D();
    float[] lon = ncDataOfLimit.get(ncDao.getVariable(ncFile, VariableName.LON).getShortName()).getData1D();
    float[][] value = ncDataOfLimit.get(ncDao.getVariable(ncFile, variableName).getShortName()).getData2D();
    if (ncDao.isContainVariableName(variableName, VariableName.UFLOW)) {
      return ncDao.getParticleFlowData(value, lon, lat, dilution, exaggerate, VariableName.UFLOW, reverseFlag, startByZero);
    } else {
      return ncDao.getParticleFlowData(value, lon, lat, dilution, exaggerate, VariableName.VFLOW, reverseFlag, startByZero);
    }
  }

  @Override
  @Cacheable
  public FlowData getParticleFlowDataOfFlowByLimitWind(NetcdfFile ncFile, float lonStart, float lonEnd, float latStart, float latEnd, Integer level, Integer time, String variableName, int dilution, int exaggerate) throws IOException, InvalidRangeException {
    Map<String, NcData> ncDataOfLimit = ncDao.getNcDataOfLimitFromVariable(ncFile, variableName, new Float[]{lonStart, lonEnd}, new Float[]{latStart, latEnd}, level, time);
    /**
     * 获取原始经纬度
     * 和数据
     */
    float[] lat = ncDataOfLimit.get(ncDao.getVariable(ncFile, VariableName.LAT).getShortName()).getData1D();
    float[] lon = ncDataOfLimit.get(ncDao.getVariable(ncFile, VariableName.LON).getShortName()).getData1D();
    float[][] value = ncDataOfLimit.get(ncDao.getVariable(ncFile, variableName).getShortName()).getData2D();
    if (ncDao.isContainVariableName(variableName, VariableName.WINDU)) {
      return ncDao.getParticleFlowDataWithWind(value, lon, lat, dilution, exaggerate, VariableName.WINDU);
    } else {
      return ncDao.getParticleFlowDataWithWind(value, lon, lat, dilution, exaggerate, VariableName.WINDV);
    }
  }

  @Override
  @Cacheable
  public FlowData getParticleFlowDataOfFlowByLimit1(NetcdfFile ncFile, float lonStart, float lonEnd, float latStart, float latEnd, int level, String variableName, int dilution, int exaggerate) throws IOException, InvalidRangeException {
    Map<String, NcData> ncDataOfLimit = ncDao.getNcDataOfLimit(ncFile, new Float[]{lonStart, lonEnd}, new Float[]{latStart, latEnd}, level);
    FlowData flowData = new FlowData();
    Header header = new Header();
    /**
     * 设置头信息
     * 固定写法（data.json这么写的）
     */
    header.setParameterCategory(2);
    header.setRefTime("2018-06-25T00:00:00.000Z");
    header.setParameterUnit("m.s-1");
    /**
     * 获取原始经纬度
     */
    float[] lat = ncDataOfLimit.get(ncDao.getVariable(ncFile, VariableName.LAT).getShortName()).getData1D();
    float[] lon = ncDataOfLimit.get(ncDao.getVariable(ncFile, VariableName.LON).getShortName()).getData1D();
    /**
     * 经纬度进行稀释
     */
    lat = ArrayUtils.arr1DDilution(lat, dilution);
    lon = ArrayUtils.arr1DDilution(lon, dilution);
    /**
     * 获取原始二维数组
     */
    NcData ncData = ncDataOfLimit.get(ncDao.getVariable(ncFile, variableName).getShortName());
    /**
     * 二维数组进行稀释
     * 行和列分别稀释
     */
    float[][] data2D = ArrayUtils.arr2DDilution(ncData.getData2D(), dilution, dilution);
    /**
     * 二维数组拼接从最后一行开始拼接
     */
    float[] data = ArrayUtils.flat2DFormFromLast(data2D);
    /**
     * 因为数组不能设置null
     * 所以使用list设置null值
     * 如果是NaN，设置为null
     */
    List<Float> list = new ArrayList<>();
    for (float datum : data) {
      if (Float.isNaN(datum)) {
        list.add(null);
      } else {
        /**
         * 二维数组乘固定倍数，可以使数据显示更明显（可以进行更改）
         */
        list.add((float) Arith.round(BigDecimal.valueOf(datum).multiply(BigDecimal.valueOf(exaggerate)).doubleValue(), 2));
      }
    }
    /**
     * 设置数据
     */
    flowData.setData(list);
    header.setNx(lon.length);
    header.setNy(lat.length);
    /**
     * lon应该从0~360，lat应该从-90~90
     * 所以数据可能要加减开始经度纬度，如果超出界限要减360和180
     * 开始纬度应该
     */

    header.setLo1(0);

    header.setLo2((lon[lon.length - 1] + 180));

    header.setLa1(lat[lat.length - 1]);
    header.setLa2(lat[0]);
    //  设置经纬度间隔
    float dx = (float) Arith.round(BigDecimal.valueOf(lon[1]).subtract(BigDecimal.valueOf(lon[0])).floatValue(), 2);
    float dy = (float) Arith.round(BigDecimal.valueOf(lat[1]).subtract(BigDecimal.valueOf(lat[0])).floatValue(), 2);
    header.setDx(dx);
    header.setDy(dy);
    /**
     * 设置参数，如果是u设置2.否则设置3，windy.js这么规定的
     * 如果是u数据
     */
    if (ncDao.getVariableName(variableName, Arrays.asList(VariableName.UFLOW.getVariableName())) != null) {
      header.setParameterNumber(2);
    }
    //  如果是v数据
    else {
      header.setParameterNumber(3);
    }
    flowData.setHeader(header);
    return flowData;
  }

  @Override
  @Cacheable
  public FlowData getParticleFlowDataOfFlowOfSlice(NetcdfFile ncFile, int level, String variableName, int dilution, int exaggerate) throws IOException, InvalidRangeException {
    Map<String, NcData> ncDataMap = ncDao.getNcDataOfSlice(ncFile, variableName, level);
    FlowData flowData = new FlowData();
    Header header = new Header();
    /**
     * 设置头信息
     * 固定写法（data.json这么写的）
     */
    header.setParameterCategory(2);
    header.setRefTime("2018-06-25T00:00:00.000Z");
    header.setParameterUnit("m.s-1");
    /**
     * 获取原始经纬度
     */
    float[] lon = ncDataMap.get(ncDao.getVariable(ncFile, VariableName.LON).getFullName()).getData1D();
    float[] lat = ncDataMap.get(ncDao.getVariable(ncFile, VariableName.LAT).getFullName()).getData1D();
    /**
     * 经纬度进行稀释
     */
    lat = ArrayUtils.arr1DDilution(lat, dilution);
    lon = ArrayUtils.arr1DDilution(lon, dilution);
    /**
     * 获取原始二维数组
     */
    NcData ncData = ncDataMap.get(variableName);

    /**
     * 二维数组进行稀释
     * 行和列分别稀释
     */
    float[][] data2D = ArrayUtils.arr2DDilution(ncData.getData2D(), dilution, dilution);
    /**
     * 二维数组拼接从最后一行开始拼接
     */
    float[] data = ArrayUtils.flat2DFormFromLast(data2D);
    /**
     * 因为数组不能设置null
     * 所以使用list设置null值
     * 如果是NaN，设置为null
     */
    List<Float> list = new ArrayList<>();
    for (float datum : data) {
      if (Float.isNaN(datum)) {
        list.add(0f);
      } else {
        /**
         * 二维数组乘固定倍数，可以使数据显示更明显（可以进行更改）
         */
        list.add((float) Arith.round(BigDecimal.valueOf(datum).multiply(BigDecimal.valueOf(exaggerate)).doubleValue(), 2));
      }
    }
    /**
     * 设置数据
     */
    flowData.setData(list);
    header.setNx(lon.length);
    header.setNy(lat.length);
    /**
     * lon应该从0~360，lat应该从-90~90
     * 所以数据可能要加减开始经度纬度，如果超出界限要减360和180
     * 开始纬度应该
     */

    header.setLo1(lon[0] + 180 > 360 ? (lon[0] - 180) : lon[0] + 180);
    header.setLo2(lon[lon.length - 1] + 180 > 360 ? (lon[lon.length - 1] - 180) : lon[lon.length - 1] + 180);
    header.setLa1(lat[lat.length - 1]);
    header.setLa2(lat[0]);
    //  设置经纬度间隔
    float dx = (float) Arith.round(BigDecimal.valueOf(lon[1]).subtract(BigDecimal.valueOf(lon[0])).floatValue(), 2);
    float dy = (float) Arith.round(BigDecimal.valueOf(lat[1]).subtract(BigDecimal.valueOf(lat[0])).floatValue(), 2);
    header.setDx(dx);
    header.setDy(dy);
    /**
     * 设置参数，如果是u设置2.否则设置3，windy.js这么规定的
     * 如果是u数据
     */
    if (ncDao.getVariableName(variableName, Arrays.asList(VariableName.UFLOW.getVariableName())) != null) {
      header.setParameterNumber(2);
    }
    //  如果是v数据
    else {
      header.setParameterNumber(3);
    }
    flowData.setHeader(header);
    return flowData;

  }

  @Override
  @Cacheable
  public FlowData getParticleFlowDataOfWaveOfLimit(NetcdfFile ncFile, float lonStart, float lonEnd, float latStart, float latEnd, Integer level, Integer time,
                                                   String variableName, int dilution, int exaggerate, boolean flagRadian) throws IOException, InvalidRangeException {
    Map<String, NcData> ncValueMap = ncDao.getNcDataOfLimitFromVariable(ncFile, VHM0, new Float[]{lonStart, lonEnd}, new Float[]{latStart, latEnd}, level, time);
    Map<String, NcData> ncDegreeMap = ncDao.getNcDataOfLimitFromVariable(ncFile, VMDR, new Float[]{lonStart, lonEnd}, new Float[]{latStart, latEnd}, level, time);
    if (ncValueMap == null || ncDegreeMap == null) {
      return null;
    }
    float[][] values = ncValueMap.get(ncDao.getVariable(ncFile, VariableName.WAVEHEIGHT).getShortName()).getData2D();
    float[][] degrees = ncDegreeMap.get(ncDao.getVariable(ncFile, VariableName.WAVEDIRECTION).getShortName()).getData2D();
    float[] lonArr = ncValueMap.get(ncDao.getVariable(ncFile, VariableName.LON).getShortName()).getData1D();
    float[] latArr = ncValueMap.get(ncDao.getVariable(ncFile, VariableName.LAT).getShortName()).getData1D();
    float[][] data2D = new float[values.length][];
    if (ncDao.isContainVariableName(variableName, VariableName.UFLOW)) {
      for (int i = 0; i < values.length; i++) {
        data2D[i] = new float[values[i].length];
        for (int j = 0; j < values[i].length; j++) {
          if (Float.isNaN(degrees[i][j]) || Float.isNaN(values[i][j])) {
            data2D[i][j] = Float.NaN;
          } else {
            data2D[i][j] = (float) Arith.round(BigDecimal.valueOf(values[i][j]).multiply(BigDecimal.valueOf(Math.cos(flagRadian ? degrees[i][j] : Math.toRadians(degrees[i][j])))).doubleValue(), 5);
          }
        }
      }
      return ncDao.getParticleFlowData(data2D, lonArr, latArr, dilution, exaggerate, VariableName.UFLOW, true, false);
    } else {
      for (int i = 0; i < values.length; i++) {
        data2D[i] = new float[values[i].length];
        for (int j = 0; j < values[i].length; j++) {
          if (Float.isNaN(degrees[i][j]) || Float.isNaN(values[i][j])) {
            data2D[i][j] = Float.NaN;
          } else {
            data2D[i][j] = (float) Arith.round(BigDecimal.valueOf(values[i][j]).multiply(BigDecimal.valueOf(Math.sin(flagRadian ? degrees[i][j] : Math.toRadians(degrees[i][j])))).doubleValue(), 5);
          }
        }
      }
      return ncDao.getParticleFlowData(data2D, lonArr, latArr, dilution, exaggerate, VariableName.VFLOW, true, false);
    }

  }

  @Override
  @Cacheable
  public FlowData getParticleFlowDataOfWaveOfLimit(NetcdfFile ncFile, float lonStart, float lonEnd, float latStart, float latEnd, Integer level, String variableName, int dilution, int exaggerate, boolean flagRadian) throws IOException, InvalidRangeException {
    return getParticleFlowDataOfWaveOfLimit(ncFile, lonStart, lonEnd, latStart, latEnd, level, null, variableName, dilution, exaggerate, flagRadian);
  }

  @Override
//  @Cacheable
  @Async
  public void getVideoFromTime(String[] filePath, FactorCondition factorCondition, Integer dilution, Integer exaggerate, Integer time) throws IOException, InvalidRangeException {
    if (CURRENTUV.equals(factorCondition.getVariableName())) {
      for (String s : filePath) {
        NetcdfFile ncFile = ncDao.getNcFile(s);
        FlowData uu = getParticleFlowDataOfFlowByLimit(ncFile, factorCondition.getStartLon(), factorCondition.getEndLon(),
            factorCondition.getStartLat(), factorCondition.getEndLat(), factorCondition.getLevel(), time, UU, dilution, exaggerate, true, false);
        FlowData vv = getParticleFlowDataOfFlowByLimit(ncFile, factorCondition.getStartLon(), factorCondition.getEndLon(),
            factorCondition.getStartLat(), factorCondition.getEndLat(), factorCondition.getLevel(), time, VV, dilution, exaggerate, true, false);
      }
    } else {
      for (String s : filePath) {
        NetcdfFile ncFile = ncDao.getNcFile(s);
        getNcContourData(ncFile, factorCondition.getVariableName(), new Float[]{factorCondition.getStartLon(), factorCondition.getEndLon()},
            new Float[]{factorCondition.getStartLat(), factorCondition.getEndLat()}, factorCondition.getLevel(), time);
      }
    }
  }

  @Override
//  @Cacheable
  @Async
  public void getFactorForCache(String filePath, FactorCondition factorCondition, Integer time) throws IOException, InvalidRangeException {
    /*  d3画流
    ContourData<FlowGridData> flowData = eddyCharacterService.getFlowGridData(ncFile, new Float[]{factorCondition.getStartLon(),
              factorCondition.getEndLon()}, new Float[]{factorCondition.getStartLat(), factorCondition.getEndLat()},
          factorCondition.getLevel(), time);*/
    /*
     * 粒子流数据加到缓存中*/
    if (!CURRENT.equals(factorCondition.getVariableName())) {
      NetcdfFile ncFile = ncDao.getNcFile(filePath);
      Map<String, NcData> ncDataOfLimitU = ncDao.getNcDataOfLimitFromVariable(ncFile, UU, new Float[]{factorCondition.getStartLon(), factorCondition.getEndLon()}, new Float[]{factorCondition.getStartLat(), factorCondition.getEndLat()}, factorCondition.getLevel(), time);
      Map<String, NcData> ncDataOfLimitV = ncDao.getNcDataOfLimitFromVariable(ncFile, VV, new Float[]{factorCondition.getStartLon(), factorCondition.getEndLon()}, new Float[]{factorCondition.getStartLat(), factorCondition.getEndLat()}, factorCondition.getLevel(), time);
      ;
     /* 对于不是uu和vv的形式而是角度和绝对值的形式使用d3
     ContourData<FlowGridData> flowData1 = eddyCharacterService.getFlowGridDataFromDegree(ncFile, new Float[]{factorCondition.getStartLon(), factorCondition.getEndLon()},
          new Float[]{factorCondition.getStartLat(), factorCondition.getEndLat()}, factorCondition.getLevel(), time);*/

      ContourData<NcGridData> salt = getNcContourData(ncFile, "salt", new Float[]{factorCondition.getStartLon(), factorCondition.getEndLon()},
          new Float[]{factorCondition.getStartLat(), factorCondition.getEndLat()}, factorCondition.getLevel(), time);

      ContourData<NcGridData> temp = getNcContourData(ncFile, "temp", new Float[]{factorCondition.getStartLon(), factorCondition.getEndLon()},
          new Float[]{factorCondition.getStartLat(), factorCondition.getEndLat()}, factorCondition.getLevel(), time);

      ContourData<NcGridData> ssh = getNcContourData(ncFile, "ssh", new Float[]{factorCondition.getStartLon(), factorCondition.getEndLon()},
          new Float[]{factorCondition.getStartLat(), factorCondition.getEndLat()}, factorCondition.getLevel(), time);
    }
  }

  @Override
  public Object[] getCommonFactorForPict(NetcdfFile ncFile, FactorCondition factorCondition, float fixedMin, float fixedMax, String colorType, Integer time, boolean reverseFlag) throws IOException, InvalidRangeException, ExecutionException, InterruptedException {
    Map<String, NcData> ncDataMap = ncDao.getNcDataWithLimit(ncFile, factorCondition.getVariableName(), new Float[]{factorCondition.getStartLon(), factorCondition.getEndLon()},
        new Float[]{factorCondition.getStartLat(), factorCondition.getEndLat()},
        factorCondition.getLevel(), time);
    System.out.println("factorCondition.getVariableName() = " + factorCondition.getVariableName());
    if (ncDataMap.get(factorCondition.getVariableName()).getData2D() == null) {
      return null;
    }
    float[][] data2D = ncDataMap.get(factorCondition.getVariableName()).getData2D();
    float min = fixedMin;
    float max = fixedMax;
    boolean flag = false;
    if (Float.isNaN(fixedMin) || Float.isNaN(fixedMax)) {
      flag = true;
      float[] minAndMax = MathUtils.minAndMax(ArrayUtils.flat2D(data2D));
      if (Float.isNaN(fixedMin)) {
        min = minAndMax[0];
      }
      if (Float.isNaN(fixedMax)) {
        max = minAndMax[1];
      }
    }
    //  不是流数据并且未跨过180
    float[] lonList = ncDataMap.get("lon").getData1D();
    if (ArrayUtils.getArrayIndex(lonList, BOUND) == 0 || ArrayUtils.getArrayIndex(lonList, BOUND) == lonList.length - 1) {
      Future<BufferedImage> task;
      if (flag) {
        if (data2D == null) {
          System.out.println("factorCondition = " + factorCondition);
        }
        task = ncPictServiceVisualization.getPictFromNcData2D(data2D, colorType, reverseFlag);
      } else {
        task = ncPictServiceVisualization.getPictFromNcData2D(data2D, fixedMin, fixedMax, colorType, reverseFlag);
      }
      //ToPictureUtil.bufferImageToImage(task.get(), "C:\\Users\\B504\\Desktop\\1022.png");
      return new Object[]{ToPictureUtil.bufferedImageToByteArray(task.get()), new float[]{min, max}, factorCondition.getVariableName()};
    }
    // 不是流数据，并且跨过了经度-180度
    else {
      Map<String, NcData> ncDataMap0 = ncDao.getNcDataWithLimit(ncFile, factorCondition.getVariableName(), new Float[]{factorCondition.getStartLon(), 180f},
          new Float[]{factorCondition.getStartLat(), factorCondition.getEndLat()}, time);
      Map<String, NcData> ncDataMap1 = ncDao.getNcDataWithLimit(ncFile, factorCondition.getVariableName(), new Float[]{-180f, factorCondition.getEndLon()},
          new Float[]{factorCondition.getStartLat(), factorCondition.getEndLat()}, time);
      Future<BufferedImage> task0;
      Future<BufferedImage> task1;
      if (flag) {
        task0 = ncPictServiceVisualization.getPictFromNcData2D(ncDataMap0.get(factorCondition.getVariableName()).getData2D(), colorType, reverseFlag);
        task1 = ncPictServiceVisualization.getPictFromNcData2D(ncDataMap1.get(factorCondition.getVariableName()).getData2D(), colorType, reverseFlag);
      } else {
        task0 = ncPictServiceVisualization.getPictFromNcData2D(ncDataMap0.get(factorCondition.getVariableName()).getData2D(), fixedMin, fixedMax, colorType, reverseFlag);
        task1 = ncPictServiceVisualization.getPictFromNcData2D(ncDataMap1.get(factorCondition.getVariableName()).getData2D(), fixedMin, fixedMax, colorType, reverseFlag);
      }
          /*ToPictureUtil.bufferImageToImage(task0.get(), "C:\\Users\\B504\\Desktop\\1022.png");
          ToPictureUtil.bufferImageToImage(task1.get(), "C:\\Users\\B504\\Desktop\\10222.png");*/
      return new Object[]{ToPictureUtil.bufferedImageToByteArray(task0.get()), ToPictureUtil.bufferedImageToByteArray(task1.get()), new float[]{min, max}, factorCondition.getVariableName()};
    }

  }

  @Override
  public Object[] getCommonFactorForPict(NetcdfFile ncFile, String variableName, float fixedMin, float fixedMax, String colorType, Integer level, Integer time, boolean reverseFlag) throws IOException, InvalidRangeException, ExecutionException, InterruptedException {
    Map<String, NcData> ncDataOfSlice = ncDao.getNcDataOfSlice(ncFile, variableName, level, time);
    if (ncDataOfSlice.get(variableName).getData2D() == null) {
      return new Object[0];
    }
    float[][] data2D = ncDataOfSlice.get(variableName).getData2D();
    float min = fixedMin;
    float max = fixedMax;
    if (Float.isNaN(fixedMin) || Float.isNaN(fixedMax)) {
      float[] minAndMax = MathUtils.minAndMax(ArrayUtils.flat2D(data2D));
      if (Float.isNaN(fixedMin)) {
        min = minAndMax[0];
      }
      if (Float.isNaN(fixedMax)) {
        max = minAndMax[1];
      }
    }
    List<float[][]> listDiv = ArrayUtils.divideArray(data2D);
    Future<BufferedImage> task0 = ncPictServiceVisualization.getPictFromNcData2D(listDiv.get(0), min, max, colorType, reverseFlag);
    Future<BufferedImage> task1 = ncPictServiceVisualization.getPictFromNcData2D(listDiv.get(1), min, max, colorType, reverseFlag);
    Future<BufferedImage> task2 = ncPictServiceVisualization.getPictFromNcData2D(listDiv.get(2), min, max, colorType, reverseFlag);
    Future<BufferedImage> task3 = ncPictServiceVisualization.getPictFromNcData2D(listDiv.get(3), min, max, colorType, reverseFlag);
    /*ToPictureUtil.bufferImageToImage(task0.get(), "C:\\Users\\B504\\Desktop\\sql\\b504" + File.separator + "task0.png");
    ToPictureUtil.bufferImageToImage(task1.get(), "C:\\Users\\B504\\Desktop\\sql\\b504" + File.separator + "task1.png");
    ToPictureUtil.bufferImageToImage(task2.get(), "C:\\Users\\B504\\Desktop\\sql\\b504" + File.separator + "task2.png");
    ToPictureUtil.bufferImageToImage(task3.get(), "C:\\Users\\B504\\Desktop\\sql\\b504" + File.separator + "task3.png");*/
    float[] lonFloat = ncDataOfSlice.get(ncDao.getVariable(ncFile, VariableName.LON).getFullName()).getData1D();
    float[] latFloat = ncDataOfSlice.get(ncDao.getVariable(ncFile, VariableName.LAT).getFullName()).getData1D();
    Float[] task0LonAndLat = new Float[]{lonFloat[0], lonFloat[lonFloat.length >> 1], latFloat[0], latFloat[latFloat.length >> 1]};
    Float[] task1LonAndLat = new Float[]{lonFloat[lonFloat.length >> 1], lonFloat[lonFloat.length - 1], latFloat[0], latFloat[latFloat.length >> 1]};
    Float[] task2LonAndLat = new Float[]{lonFloat[0], lonFloat[lonFloat.length >> 1], latFloat[latFloat.length >> 1], latFloat[latFloat.length - 1]};
    Float[] task3LonAndLat = new Float[]{lonFloat[lonFloat.length >> 1], lonFloat[lonFloat.length - 1], latFloat[latFloat.length >> 1], latFloat[latFloat.length - 1]};
    return new Object[]{ToPictureUtil.bufferedImageToByteArray(task0.get()), ToPictureUtil.bufferedImageToByteArray(task1.get()),
        ToPictureUtil.bufferedImageToByteArray(task2.get()), ToPictureUtil.bufferedImageToByteArray(task3.get()),
        new float[]{min, max}, variableName, task0LonAndLat, task1LonAndLat, task2LonAndLat, task3LonAndLat};
  }

  @Override
  public Object[] getCurrentFactorForPict(NetcdfFile ncFile, FactorCondition factorCondition, float fixedMin, float fixedMax, String colorType, Integer time, boolean reverseFlag) throws IOException, InvalidRangeException, ExecutionException, InterruptedException {
    Map<String, NcData> uuDataMap = ncDao.getNcDataWithLimit(ncFile, UU, new Float[]{factorCondition.getStartLon(), factorCondition.getEndLon()},
        new Float[]{factorCondition.getStartLat(), factorCondition.getEndLat()}, factorCondition.getLevel(), time);
    Map<String, NcData> vvDataMap = ncDao.getNcDataWithLimit(ncFile, VV, new Float[]{factorCondition.getStartLon(), factorCondition.getEndLon()},
        new Float[]{factorCondition.getStartLat(), factorCondition.getEndLat()}, factorCondition.getLevel(), time);
    if (uuDataMap == null || vvDataMap == null || uuDataMap.get(UU) == null || vvDataMap.get(VV) == null) {
      return null;
    }
    float[][] data2Du = uuDataMap.get(UU).getData2D();
    float[][] data2Dv = vvDataMap.get(VV).getData2D();
    float[][] data2D = ArrayUtils.getDataFromUV(data2Du, data2Dv);
    float min = fixedMin;
    float max = fixedMax;
    boolean flag = false;
    if (Float.isNaN(fixedMin) || Float.isNaN(fixedMax)) {
      flag = true;
      float[] minAndMax = MathUtils.minAndMax(ArrayUtils.flat2D(data2D));
      if (Float.isNaN(fixedMin)) {
        min = minAndMax[0];
      }
      if (Float.isNaN(fixedMax)) {
        max = minAndMax[1];
      }
    }
    float[] lonList = uuDataMap.get("lon").getData1D();
    //  如果没有跨过-180度
    if (ArrayUtils.getArrayIndex(lonList, BOUND) == 0 || ArrayUtils.getArrayIndex(lonList, BOUND) == lonList.length - 1) {
      Future<BufferedImage> task;
      if (flag) {
        task = ncPictServiceVisualization.getPictFromNcData2D(data2D, colorType, reverseFlag);
      } else {
        task = ncPictServiceVisualization.getPictFromNcData2D(data2D, fixedMin, fixedMax, colorType, reverseFlag);
      }
      return new Object[]{ToPictureUtil.bufferedImageToByteArray(task.get()), new float[]{min, max}, factorCondition.getVariableName()};
    } else {
      Map<String, NcData> uuDataMap0 = ncDao.getNcDataWithLimit(ncFile, UU, new Float[]{factorCondition.getStartLon(), 180f},
          new Float[]{factorCondition.getStartLat(), factorCondition.getEndLat()},
          factorCondition.getLevel(), time);
      Map<String, NcData> uuDataMap1 = ncDao.getNcDataWithLimit(ncFile, UU, new Float[]{-180f, factorCondition.getStartLon()},
          new Float[]{factorCondition.getStartLat(), factorCondition.getEndLat()},
          factorCondition.getLevel(), time);
      Map<String, NcData> vvDataMap0 = ncDao.getNcDataWithLimit(ncFile, VV, new Float[]{factorCondition.getStartLon(), 180f},
          new Float[]{factorCondition.getStartLat(), factorCondition.getEndLat()},
          factorCondition.getLevel(), time);
      Map<String, NcData> vvDataMap1 = ncDao.getNcDataWithLimit(ncFile, VV, new Float[]{-180f, factorCondition.getStartLon()},
          new Float[]{factorCondition.getStartLat(), factorCondition.getEndLat()},
          factorCondition.getLevel(), time);
      Future<BufferedImage> task0;
      Future<BufferedImage> task1;
      float[][] data0 = ArrayUtils.getDataFromUV(uuDataMap0.get(UU).getData2D(), vvDataMap0.get(VV).getData2D());
      float[][] data1 = ArrayUtils.getDataFromUV(uuDataMap1.get(UU).getData2D(), vvDataMap1.get(VV).getData2D());
      if (flag) {
        task0 = ncPictServiceVisualization.getPictFromNcData2D(data0, colorType, reverseFlag);
        task1 = ncPictServiceVisualization.getPictFromNcData2D(data1, colorType, reverseFlag);
      } else {
        task0 = ncPictServiceVisualization.getPictFromNcData2D(data0, fixedMin, fixedMax, colorType, reverseFlag);
        task1 = ncPictServiceVisualization.getPictFromNcData2D(data1, fixedMin, fixedMax, colorType, reverseFlag);
      }
      return new Object[]{ToPictureUtil.bufferedImageToByteArray(task0.get()), ToPictureUtil.bufferedImageToByteArray(task1.get()), new float[]{min, max}, factorCondition.getVariableName()};
    }
  }

  @Override
  public Object[] getCurrentFactorForPict(NetcdfFile ncFile, float fixedMin, float fixedMax, String colorType, Integer level, Integer time, boolean reverseFlag) throws IOException, InvalidRangeException, ExecutionException, InterruptedException {
    Map<String, NcData> uuDataMap = ncDao.getNcDataOfSlice(ncFile, UU, level, time);
    Map<String, NcData> vvDataMap = ncDao.getNcDataOfSlice(ncFile, VV, level, time);
    if (uuDataMap == null || vvDataMap == null || uuDataMap.get(UU) == null || vvDataMap.get(VV) == null) {
      return new Object[0];
    }
    float[][] data2Du = uuDataMap.get(UU).getData2D();
    float[][] data2Dv = vvDataMap.get(VV).getData2D();
    float[][] data2D = ArrayUtils.getDataFromUV(data2Du, data2Dv);
    float min = fixedMin;
    float max = fixedMax;
    if (Float.isNaN(fixedMin) || Float.isNaN(fixedMax)) {
      float[] minAndMax = MathUtils.minAndMax(ArrayUtils.flat2D(data2D));
      if (Float.isNaN(fixedMin)) {
        min = minAndMax[0];
      }
      if (Float.isNaN(fixedMax)) {
        max = minAndMax[1];
      }
    }
    List<float[][]> listDiv = ArrayUtils.divideArray(data2D);
    Future<BufferedImage> task0 = ncPictServiceVisualization.getPictFromNcData2D(listDiv.get(0), min, max, colorType, reverseFlag);
    Future<BufferedImage> task1 = ncPictServiceVisualization.getPictFromNcData2D(listDiv.get(1), min, max, colorType, reverseFlag);
    Future<BufferedImage> task2 = ncPictServiceVisualization.getPictFromNcData2D(listDiv.get(2), min, max, colorType, reverseFlag);
    Future<BufferedImage> task3 = ncPictServiceVisualization.getPictFromNcData2D(listDiv.get(3), min, max, colorType, reverseFlag);
    float[] lonFloat = uuDataMap.get(ncDao.getVariable(ncFile, VariableName.LON).getFullName()).getData1D();
    float[] latFloat = uuDataMap.get(ncDao.getVariable(ncFile, VariableName.LAT).getFullName()).getData1D();
    Float[] task0LonAndLat = new Float[]{lonFloat[0], lonFloat[lonFloat.length >> 1], latFloat[0], latFloat[latFloat.length >> 1]};
    Float[] task1LonAndLat = new Float[]{lonFloat[lonFloat.length >> 1], lonFloat[lonFloat.length - 1], latFloat[0], latFloat[latFloat.length >> 1]};
    Float[] task2LonAndLat = new Float[]{lonFloat[0], lonFloat[lonFloat.length >> 1], latFloat[latFloat.length >> 1], latFloat[latFloat.length - 1]};
    Float[] task3LonAndLat = new Float[]{lonFloat[lonFloat.length >> 1], lonFloat[lonFloat.length - 1], latFloat[latFloat.length >> 1], latFloat[latFloat.length - 1]};

    /*ToPictureUtil.bufferImageToImage(task0.get(), "C:\\Users\\B504\\Desktop\\sql\\b504" + File.separator + "task0.png");
    ToPictureUtil.bufferImageToImage(task1.get(), "C:\\Users\\B504\\Desktop\\sql\\b504" + File.separator + "task1.png");
    ToPictureUtil.bufferImageToImage(task2.get(), "C:\\Users\\B504\\Desktop\\sql\\b504" + File.separator + "task2.png");
    ToPictureUtil.bufferImageToImage(task3.get(), "C:\\Users\\B504\\Desktop\\sql\\b504" + File.separator + "task3.png");*/
    return new Object[]{ToPictureUtil.bufferedImageToByteArray(task0.get()), ToPictureUtil.bufferedImageToByteArray(task1.get()),
        ToPictureUtil.bufferedImageToByteArray(task2.get()), ToPictureUtil.bufferedImageToByteArray(task3.get()),
        new float[]{min, max}, CURRENT, task0LonAndLat, task1LonAndLat, task2LonAndLat, task3LonAndLat};

  }

  @Override
  public Object[] getGlobelPng(NetcdfFile ncFile, String variableName, float fixedMin, float fixedMax, String colorType, Integer level, Integer time, boolean reverseFlag) throws IOException, InvalidRangeException, ExecutionException, InterruptedException {
    // 如果不是流场数据直接获取即可
    if (!CURRENTUV.equals(variableName)) {
      float[][] data2D = ncDao.getNcDataOfSlice(ncFile, variableName, level, time).get(variableName).getData2D();
      if (data2D == null) {
        log.error("数据为空，请检查数据");
        return new Object[1];
      }

      BufferedImage bi = ncPictServiceVisualization.getPictFromData2DByThread(data2D, fixedMin, fixedMax, colorType, reverseFlag);
      byte[] bytes = ToPictureUtil.bufferedImageToByteArray(bi);
      float min = fixedMin;
      float max = fixedMax;

      if (Float.isNaN(fixedMin) || Float.isNaN(fixedMax)) {

        float[] minAndMax = MathUtils.minAndMax(data2D);
        if (Float.isNaN(fixedMin)) {
          min = minAndMax[0];
        }
        if (Float.isNaN(fixedMax)) {
          max = minAndMax[1];
        }
      }
      return new Object[]{bytes, new float[]{min, max}, variableName};

    } else {
      float[][] data2DU = ncDao.getNcDataOfSlice(ncFile, UU).get(variableName).getData2D();
      float[][] data2DV = ncDao.getNcDataOfSlice(ncFile, VV).get(variableName).getData2D();
      float[][] dataFromUV = ArrayUtils.getDataFromUV(data2DU, data2DV);

      BufferedImage bi = ncPictServiceVisualization.getPictFromData2DByThread(dataFromUV, fixedMin, fixedMax, colorType, reverseFlag);
      float min = fixedMin;
      float max = fixedMax;
      if (Float.isNaN(fixedMin) || Float.isNaN(fixedMax)) {

        float[] minAndMax = MathUtils.minAndMax(dataFromUV);
        if (Float.isNaN(fixedMin)) {
          min = minAndMax[0];
        }
        if (Float.isNaN(fixedMax)) {
          max = minAndMax[1];
        }
      }
      byte[] bytes = ToPictureUtil.bufferedImageToByteArray(bi);
      return new Object[]{bytes, new float[]{min, max}, CURRENTUV};
    }

  }
}
